
`include "common_header.verilog"

//  *************************************************************************
//  File : eth40g_pcs64_ll_top.v
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2009 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Denis Poverennyy
//  info@morethanip.com
//  *************************************************************************
//  Description : 40G Channelized PCS with 64 data path: Top Level Structure
//  Version     : $Id: eth40g_pcs64_ll_top.v,v 1.6 2014/08/08 16:38:13 ts Exp $
//  *************************************************************************

module eth40g_pcs64_ll_top (


        ref_clk,
        reset_ref_clk,
        reg_clk,        
        reset_reg_clk,        
        sd_tx_clk,
        reset_sd_tx_clk,               
        sd_rx_clk,        
        reset_sd_rx_clk,
 
 `ifdef  MTIPPCS_SERDES_CLK_EN_PINS   
 
        sd_tx_clk_ena,
        sd_rx_clk_ena,

 `endif
 
        cgmii_txc,
        cgmii_txd,
        cgmii_txclk_ena,
        sd0_rx,
        sd1_rx,
        sd2_rx,
        sd3_rx,
        signal_det,
        sd0_tx,
        sd1_tx,
        sd2_tx,
        sd3_tx,
        cgmii_rxc,
        cgmii_rxd,
        xlgmii_rxt0_next,
        cgmii_rxclk_ena,
        ber_timer_done,
        block_lock,
        align_done,
        hi_ber,

 `ifdef MTIPPCS_FEC_ENA
 
        fec_ena_tx,
        fec_ena_rx,

  `ifdef MTIPPCS_FECERR_ENA

        fec_err_ena,
  
  `endif
  
        fec_locked,
        fec_cerr,
        fec_ncerr,
 `endif

 `ifdef MTIPPCS82_EEE_ENA
 
        lpi_tick_tx,
        lpi_tick_rx,
        lpi_fw,
        energy_detect,
        tx_lpi_mode,
        tx_lpi_state,
        rx_lpi_active,
        rx_lpi_mode,
        rx_lpi_state,
        
  `endif
 
        reg_rden,
        reg_wren,
        reg_addr,
        reg_din,
        reg_dout,
        reg_busy);

`include "mtip_pcs100g_pack_package.verilog"

input   ref_clk;                                //  reference clock
input   reset_ref_clk;                          //  async active high reset
input   [3:0] sd_tx_clk;                        //  Serdes Tx clock
input   [3:0] sd_rx_clk;                        //  Serdes Rx clock

`ifdef  MTIPPCS_SERDES_CLK_EN_PINS   

 input  [3:0] sd_tx_clk_ena;                    //  Serdes Tx clock enable
 input  [3:0] sd_rx_clk_ena;                    //  Serdes Rx clock enable

`endif

input   [3:0] reset_sd_rx_clk;                  //  async active high reset
input   [SERDES_WIDTH - 1:0] sd0_rx;            //  data 0 input
input   [SERDES_WIDTH - 1:0] sd1_rx;            //  data 1 input
input   [SERDES_WIDTH - 1:0] sd2_rx;            //  data 2 input
input   [SERDES_WIDTH - 1:0] sd3_rx;            //  data 3 input
input   [3:0] signal_det;                       //  if low SERDES' signals are not valid
input   [3:0] reset_sd_tx_clk;                  //  async active high reset
output  [SERDES_WIDTH - 1:0] sd0_tx;            //  data 0 output
output  [SERDES_WIDTH - 1:0] sd1_tx;            //  data 1 output
output  [SERDES_WIDTH - 1:0] sd2_tx;            //  data 2 output
output  [SERDES_WIDTH - 1:0] sd3_tx;            //  data 3 output
input   [7:0] cgmii_txc;                        //  XL/CGMII transmit control
input   [63:0] cgmii_txd;                       //  XL/CGMII transmit data
output  cgmii_txclk_ena;                        //  XL/CGMII transmit clock enable
output  [7:0] cgmii_rxc;                        //  XL/CGMII receive control
output  [63:0] cgmii_rxd;                       //  XL/CGMII receive data
output  xlgmii_rxt0_next;                       //  Advance indication if TERM block without data is next after current 
output  cgmii_rxclk_ena;                        //  XL/CGMII receive clock enable
output  ber_timer_done;                         //  Hi BER measure window
output  [3:0] block_lock;                       //  Block lock state reached
output  align_done;                             //  Alignment marker lock state reached
output  hi_ber;                                 //  High Bit Error

`ifdef MTIPPCS_FEC_ENA

 input  [3:0] fec_ena_tx;                       //  FEC Enable (Tx)
 input  [3:0] fec_ena_rx;                       //  FEC Enable (Rx)

 `ifdef MTIPPCS_FECERR_ENA
 
  input [3:0] fec_err_ena;                      //  FEC Error Indication Enable

  `endif

 output [3:0] fec_locked;                       //  FEC Decoder Locked
 output [3:0] fec_cerr;                         //  FEC Corrected Blocks Counter Increment
 output [3:0] fec_ncerr;                        //  FEC Uncorrected Blocks Counter Increment

`endif

`ifdef MTIPPCS82_EEE_ENA 

 input  lpi_tick_tx;		                // Tx 1us timer tick asserted for one reference clock
 input  lpi_tick_rx;		                // Rx 1us timer tick asserted for one reference clock                                        
 input  lpi_fw;                                 // Xake mode for the LPI transmit and receive functions
 input  [3:0] energy_detect;		        // Indication from Serdes that it detects signaling					
 output [1:0] tx_lpi_mode;                      // LPI transmit state
 output [2:0] tx_lpi_state;                     // LPI Transmit State Machine States
 output rx_lpi_active;                          // Receiver is in a low power state 
 output rx_lpi_mode;                            // LPI Receive state
 output [2:0] rx_lpi_state;                     // LPI Receive State Machine States

`endif

input   reg_clk;                                //  Reference Interface Clock
input   reset_reg_clk;                          //  async active high reset
input   reg_rden;                               //  Register Read Strobe
input   reg_wren;                               //  Register Write Strobe
input   [15:0] reg_addr;                        //  Register Address
input   [15:0] reg_din;                         //  Write Data from Host Bus
output  [15:0] reg_dout;                        //  Read Data to Host Bus
output  reg_busy;                               //  Register Interface Busy

wire    [SERDES_WIDTH - 1:0] sd0_tx;
wire    [SERDES_WIDTH - 1:0] sd1_tx;
wire    [SERDES_WIDTH - 1:0] sd2_tx;
wire    [SERDES_WIDTH - 1:0] sd3_tx;
wire    cgmii_txclk_ena;
wire    [7:0] cgmii_rxc;
wire    [63:0] cgmii_rxd;
wire    xlgmii_rxt0_next; 
wire    cgmii_rxclk_ena;
wire    ber_timer_done;
wire    [3:0] block_lock;
wire    align_done;
wire    hi_ber;

`ifdef MTIPPCS_FEC_ENA

 wire   [3:0] fec_locked;
 wire   [3:0] fec_cerr;
 wire   [3:0] fec_ncerr;

`endif

`ifdef MTIPPCS82_EEE_ENA 

 wire   [1:0] tx_lpi_mode;
 wire   [2:0] tx_lpi_state;
 wire   rx_lpi_active;
 wire   rx_lpi_mode;
 wire   [2:0] rx_lpi_state;

`endif

wire    [15:0] reg_dout;
wire    reg_busy;

wire    cgmii_txclk_ena_int;                    //  XL/CGMII transmit clock enable
wire    align_lock;                             //  Lane Alignment Done
wire    [7:0] lane_map;                         //  Lane Mapping
wire    block_lock_int;                         //  Block lock state reached
wire    [3:0] block_lock_l;                     //  Per-Lane Block Lock
wire    [3:0] align_lock_l;                     //  Per-Lane Alignment Indication
wire    hi_ber_int;                             //  High Bit Error
wire    [15:0] vl_intvl;                        //  AM Period value
wire    [21:0] ber_count;                       //  BER Counter
wire    [21:0] err_block_cnt;                   //  Errored Block Counter
wire    [15:0] pat_err_cnt;                     //  Test Pattern Error Counter
wire    bip8_stat_0;                            //  VL0 BIP8 Error Indication
wire    bip8_stat_1;                            //  VL1 BIP8 Error Indication
wire    bip8_stat_2;                            //  VL2 BIP8 Error Indication
wire    bip8_stat_3;                            //  VL3 BIP8 Error Indication
wire    ber_count_read;                         //  BER Counter Read Enable
wire    err_block_cnt_rd;                       //  Errored Block Counter Read Enable
wire    tx_en_gen_pat;                          //  Transmit Test Mode Enable
wire    r_test_mode;                            //  Receive Test Mode Enable
wire    pat_err_cnt_rd;                         //  Test Pattern Error Counter Read Enable
wire    sw_reset;                               //  Sofware Reset
wire    loopback_ena;                           //  Loopback Enable
wire    ber_timer_short;                        //  Short BER Timer Value Indication
wire    [3:0] tx_lane_thresh;                   //  4 bit per lane tx decoupling buffer level threshold (5..7 depending on refclk)

`ifdef MTIPPCS82_EEE_ENA 

 wire   rx_lpi_indication;                      // Rx LPI indication
 wire   tx_lpi_indication;                      // Tx LPI indication
 wire   [15:0] wake_error_counter;
 wire   wake_error_counter_rd;
 wire   lpi_fw_comb_tx;
 wire   lpi_fw_comb_rx;
 wire   lpi_fw_ena;
 wire   lpi_fw_ena_tx;
 wire   lpi_fw_ena_rx;
 wire   lpi_fw_tx;
 wire   lpi_fw_rx;
 wire   [3:0] energy_detect_sy;
 wire   energy_detect_comb;            

 `ifdef MTIPPCS_FEC_ENA

  wire  [3:0] fec_ena_tx_sy;
  wire  fec_ena_tx_comb;
  wire  [3:0] fec_ena_rx_sy;
  wire  fec_ena_rx_comb;

 `endif

`endif

//  Signal Synchronization
//  ----------------------

wire    tx_en_gen_pat_s;
wire    r_test_mode_s;
wire    sw_reset_s;
wire    [15:0] vl_intvl_s;

mtip_xsync #(16) U_SVLINTV (
 
          .data_in(vl_intvl),
          .reset(reset_ref_clk),
          .clk(ref_clk),
          .data_s(vl_intvl_s));

redge_ckxing U_SWRS (

   .reset(reset_reg_clk),
   .clk(reg_clk),
   .sig(sw_reset),
   .reset_clk_o(reset_ref_clk),
   .clk_o(ref_clk),
   .sig_o(sw_reset_s));

mtip_xsync #(1) U_RXS (
 
          .data_in(r_test_mode),
          .reset(reset_ref_clk),
          .clk(ref_clk),
          .data_s(r_test_mode_s));

mtip_xsync #(1) U_TXS (
 
          .data_in(tx_en_gen_pat),
          .reset(reset_ref_clk),
          .clk(ref_clk),
          .data_s(tx_en_gen_pat_s));

`ifdef MTIPPCS82_EEE_ENA 

 mtip_xsync #(2) U_LPI_RX_SYNC (
 
        .data_in({lpi_fw, lpi_fw_ena}),
        .reset(reset_ref_clk),
        .clk(ref_clk),
        .data_s({ lpi_fw_rx, lpi_fw_ena_rx}));

 assign lpi_fw_comb_rx = lpi_fw_ena_rx | lpi_fw_rx;

 mtip_xsync #(4) U_ENERG_SYNC (
 
        .data_in(energy_detect),
        .reset(reset_ref_clk),
        .clk(ref_clk),
        .data_s(energy_detect_sy));

 assign energy_detect_comb = &energy_detect_sy;

 `ifdef MTIPPCS_FEC_ENA

   mtip_xsync #(4) U_FEC_RX_SYNC (

        .data_in(fec_ena_rx),
        .reset(reset_ref_clk),
        .clk(ref_clk),
        .data_s(fec_ena_rx_sy));

  assign fec_ena_rx_comb = &fec_ena_rx_sy;

 `endif

`endif

assign ber_timer_short = (vl_intvl_s < 16'd 16383)? 1'b 1: 1'b 0;

p8264_top_rx_40g U_RX (

        .reset_rxclk(reset_ref_clk),
        .reset_sd_rx_clk(reset_sd_rx_clk),
        .cgmii_rxclk(ref_clk),
        .sd_rx_clk(sd_rx_clk),
    
     `ifdef MTIPPCS_SERDES_CLK_EN_PINS
     
        .sd_rx_clk_ena(sd_rx_clk_ena),
     
     `else
     
        .sd_rx_clk_ena(4'b 1111),
        
     `endif 
     
        .signal_det(signal_det),
        .sd0_rx(sd0_rx),
        .sd1_rx(sd1_rx),
        .sd2_rx(sd2_rx),
        .sd3_rx(sd3_rx),
        .cgmii_txc(cgmii_txc),
        .cgmii_txd(cgmii_txd),
        .cgmii_txclk_ena(cgmii_txclk_ena_int),
        .cgmii_rxc(cgmii_rxc),
        .cgmii_rxd(cgmii_rxd),
        .cgmii_rxclk_ena(cgmii_rxclk_ena),
        .xlgmii_rxt0_next(xlgmii_rxt0_next),
        .sw_reset(sw_reset_s),
        .loopback_ena(loopback_ena),
        .ber_count_read(ber_count_read),
        .err_block_cnt_rd(err_block_cnt_rd),
        .r_test_mode(r_test_mode_s),
        .pat_err_cnt_rd(pat_err_cnt_rd),

   `ifdef MTIPPCS_FEC_ENA
   
        .fec_ena(fec_ena_rx),
   
    `ifdef MTIPPCS_FECERR_ENA
   
        .fec_err_ena(fec_err_ena),
   
    `endif
   
        .fec_locked(fec_locked),
        .fec_cerr(fec_cerr),
        .fec_ncerr(fec_ncerr),

   `endif 
   
   `ifdef MTIPPCS82_EEE_ENA 
   
        .lpi_tick(lpi_tick_rx),		
        .lpi_fw(lpi_fw_comb_rx),                       

      `ifdef MTIPPCS_FEC_ENA
      
        .scr_bypass_enable(fec_ena_rx_comb),
      
      `else
      
        .scr_bypass_enable(1'b 0),        
      
      `endif  

        .energy_detect(energy_detect_comb),		
        .rx_lpi_active(rx_lpi_active),          
        .rx_lpi_mode(rx_lpi_mode),            
        .rx_lpi_state(rx_lpi_state),           
        .rx_fw_state(),		
        .wake_error_counter_inc(),
        .wake_error_counter(wake_error_counter),
        .wake_error_counter_rd(wake_error_counter_rd),
        .rx_lpi_indication(rx_lpi_indication),

   `endif 
   
        .block_lock(block_lock_int),
        .block_lock_l(block_lock_l),
        .align_lock(align_lock),
        .align_lock_l(align_lock_l),
        .hi_ber(hi_ber_int),
        .vl_intvl(vl_intvl_s),
        .vl_0_enc(24'h 477690),
        .vl_1_enc(24'h e6c4f0),
        .vl_2_enc(24'h 9b65c5),
        .vl_3_enc(24'h 3d79a2),  
        .ber_timer_short(ber_timer_short),
        .ber_timer_done(ber_timer_done),
        .lane_map(lane_map),
        .err_block_cnt(err_block_cnt),
        .ber_count(ber_count),
        .pat_err_cnt(pat_err_cnt),
        .bip8_err_stat_0(bip8_stat_0),
        .bip8_err_stat_1(bip8_stat_1),
        .bip8_err_stat_2(bip8_stat_2),
        .bip8_err_stat_3(bip8_stat_3));

assign cgmii_txclk_ena = cgmii_txclk_ena_int;

p8264_top_tx_40g U_TX (

        .reset_txclk(reset_ref_clk),
        .reset_sd_tx_clk(reset_sd_tx_clk),
        .cgmii_txclk(ref_clk),
        .sd_tx_clk(sd_tx_clk),
        
     `ifdef MTIPPCS_SERDES_CLK_EN_PINS
     
        .sd_tx_clk_ena(sd_tx_clk_ena),
     
     `else
     
        .sd_tx_clk_ena(4'b 1111),
        
     `endif   
        
        .cgmii_txc(cgmii_txc),
        .cgmii_txd(cgmii_txd),
        .cgmii_txclk_ena(cgmii_txclk_ena_int),
        .sd0_tx(sd0_tx),
        .sd1_tx(sd1_tx),
        .sd2_tx(sd2_tx),
        .sd3_tx(sd3_tx),

   `ifdef MTIPPCS_FEC_ENA
   
        .fec_ena(fec_ena_tx),

   `endif

   `ifdef MTIPPCS82_EEE_ENA 
   
        .lpi_tick(lpi_tick_tx),
        .lpi_fw(lpi_fw_comb_tx),
    
      `ifdef MTIPPCS_FEC_ENA
      
        .scr_bypass_enable(fec_ena_tx_comb),
      
      `else
      
        .scr_bypass_enable(1'b 0),        
      
      `endif         
      
        .tx_lpi_mode(tx_lpi_mode),
        .tx_lpi_state(tx_lpi_state),
        .tx_lpi_indication(tx_lpi_indication),
   
   `endif
      
        .sw_reset(sw_reset_s),
        .vl_intvl(vl_intvl_s),       
        .vl_0_enc(24'h 477690),
        .vl_1_enc(24'h e6c4f0),
        .vl_2_enc(24'h 9b65c5),
        .vl_3_enc(24'h 3d79a2),        
        .tx_en_gen_pat(tx_en_gen_pat),
        .tx_lane_thresh(tx_lane_thresh));

register_map_pcs_40g U_REG (

`ifdef MTIPPCS40_VENDORCFGREGS
   
   .vl_intvl(vl_intvl),
   .tx_lane_thresh(tx_lane_thresh),
   
`endif

`ifdef MTIPPCS82_EEE_ENA 

    .lpi_fw(lpi_fw_ena),
    .wake_error_counter(wake_error_counter),
    .wake_error_counter_rd(wake_error_counter_rd),
    .tx_lpi_indication(tx_lpi_indication),
    .rx_lpi_indication(rx_lpi_indication),

`endif

   .reset_rx_clk(reset_ref_clk),
   .reset_tx_clk(reset_ref_clk),
   .reset_reg_clk(reset_reg_clk),
   .rx_clk(ref_clk),
   .tx_clk(ref_clk),
   .reg_clk(reg_clk),
   .rx_err(1'b 0),
   .tx_err(1'b 0),
   .link_status(align_lock),
   .lane_map(lane_map),
   .block_lock(block_lock_int),
   .block_lock_3_0(block_lock_l),
   .align_lock(align_lock),
   .align_lock_3_0(align_lock_l),
   .hi_ber(hi_ber_int),
   .ber_count(ber_count),
   .err_block_cnt(err_block_cnt),
   .pat_err_cnt(pat_err_cnt),
   .bip8_stat_0(bip8_stat_0),
   .bip8_stat_1(bip8_stat_1),
   .bip8_stat_2(bip8_stat_2),
   .bip8_stat_3(bip8_stat_3),
   .ber_count_read(ber_count_read),
   .err_block_cnt_rd(err_block_cnt_rd),
   .tx_test_mode(tx_en_gen_pat),
   .rx_test_mode(r_test_mode),
   .pat_err_cnt_rd(pat_err_cnt_rd),
   .reg_rd(reg_rden),
   .reg_wr(reg_wren),
   .reg_addr(reg_addr),
   .reg_din(reg_din),
   .reg_dout(reg_dout),
   .reg_busy(reg_busy),
   .sw_reset(sw_reset),
   .loopback_ena(loopback_ena));

assign block_lock = block_lock_l;
assign align_done = align_lock;
assign hi_ber     = hi_ber_int;

endmodule // module eth40g_pcs64_ll_top